/*
 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2018年5月24日
 * <修改描述:>
 */
package com.tx.core.method.resolver;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.MethodParameter;
import org.springframework.core.OrderComparator;
import org.springframework.lang.Nullable;

import com.tx.core.method.container.NativeInvokeContainer;
import com.tx.core.method.databinder.NativeDataBinderFactory;
import com.tx.core.method.exceptions.MethodInvokeArgIllegalException;
import com.tx.core.method.request.NativeInvokeRequest;

/**
 * 本地方法参数解析器<br/>
 * <功能详细描述>
 * 
 * @author  Administrator
 * @version  [版本号, 2018年5月24日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class NativeMethodArgumentResolverComposite {
    
    /** 方法参数解析器 */
    private final List<NativeMethodArgumentResolver> argumentResolvers = new ArrayList<>();
    
    /** 解析器映射缓存 */
    private final Map<MethodParameter, NativeMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap<>(
            256);
    
    /**
     * 是否能支持该方法参数<br/>
     * <功能详细描述>
     * @param parameter
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public boolean supportsParameter(MethodParameter parameter) {
        return getArgumentResolver(parameter) != null;
    }
    
    /**
     * 决策、解决对应的方法参数的实体<br/>
     * <功能详细描述>
     * @param methodParameter
     * @param container
     * @param invokeRequest
     * @param dataBinderFactory
     * @return
     * @throws Exception [参数说明]
     * 
     * @return Object [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public Object resolveArgument(MethodParameter methodParameter,
            NativeInvokeContainer container, NativeInvokeRequest invokeRequest,
            NativeDataBinderFactory dataBinderFactory) throws Exception {
        NativeMethodArgumentResolver resolver = getArgumentResolver(
                methodParameter);
        if (resolver == null) {
            throw new MethodInvokeArgIllegalException(
                    "Unsupported parameter type ["
                            + methodParameter.getParameterType().getName()
                            + "]. supportsParameter should be called first.");
        }
        return resolver.resolveArgument(methodParameter,
                container,
                invokeRequest,
                dataBinderFactory);
    }
    
    /**
     * find匹配的参数解析器<br/>
     * <功能详细描述>
     * @param parameter
     * @return [参数说明]
     * 
     * @return NativeMethodArgumentResolver [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    protected NativeMethodArgumentResolver getArgumentResolver(
            MethodParameter parameter) {
        NativeMethodArgumentResolver result = this.argumentResolverCache
                .get(parameter);
        if (result == null) {
            for (NativeMethodArgumentResolver resolver : this.argumentResolvers) {
                if (resolver.supportsParameter(parameter)) {
                    result = resolver;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }
    
    /**
     * 添加解析器<br/>
     * <功能详细描述>
     * @param resolver
     * @return [参数说明]
     * 
     * @return NativeMethodArgumentResolverComposite [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public NativeMethodArgumentResolverComposite addResolver(
            NativeMethodArgumentResolver resolver) {
        this.argumentResolvers.add(resolver);
        return this;
    }
    
    /**
     * 添加解析器<br/>
     * <功能详细描述>
     * @param resolvers
     * @return [参数说明]
     * 
     * @return NativeMethodArgumentResolverComposite [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public NativeMethodArgumentResolverComposite addResolvers(
            @Nullable NativeMethodArgumentResolver... resolvers) {
        if (resolvers != null) {
            Collections.addAll(this.argumentResolvers, resolvers);
        }
        return this;
    }
    
    /**
     * 添加解析器<br/>
     * <功能详细描述>
     * @param resolvers
     * @return [参数说明]
     * 
     * @return NativeMethodArgumentResolverComposite [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public NativeMethodArgumentResolverComposite addResolvers(
            @Nullable List<? extends NativeMethodArgumentResolver> resolvers) {
        if (resolvers != null) {
            this.argumentResolvers.addAll(resolvers);
        }
        return this;
    }
    
    /**
     * 添加解析器<br/>
     * <功能详细描述>
     * @param resolvers
     * @return [参数说明]
     * 
     * @return NativeMethodArgumentResolverComposite [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public NativeMethodArgumentResolverComposite sort() {
        Collections.sort(this.argumentResolvers, OrderComparator.INSTANCE);
        return this;
    }
    
    /**
     * 返回一个仅能只读的参数解析器<br/>
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return List<NativeMethodArgumentResolver> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<NativeMethodArgumentResolver> getResolvers() {
        return Collections.unmodifiableList(this.argumentResolvers);
    }
    
    /**
     * 清空解析器及解析器缓存<br/>
     * <功能详细描述> [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void clear() {
        this.argumentResolvers.clear();
        this.argumentResolverCache.clear();
    }
}
